Overload the = operator

How do you overload the = operator for custom types to the right?
Eg. returning an int:

struct MyType {}
void ::= (int &Value, MyType MyTypeVar)    { Value = 5 }
 
MyType NewMyType
int Test = NewMyType
print "Test : " Test "\n"

SystemAdmin - Mon Feb 14 11:56:08 EST 2011

Re: Overload the = operator
SystemAdmin - Mon Feb 14 15:38:00 EST 2011

struct MyType {}
 
int& ::= (int& intValue, MyType myTypeInstance) { 
    intValue = (int addr_ myTypeInstance);
    return intValue;
}
 
MyType& ::= (MyType& myTypeInstanceRef, int intValue) { 
    myTypeInstanceRef = (MyType addr_ intValue);
    return myTypeInstanceRef;
}
 
int intOf(MyType myTypeInstance) { 
    return (int addr_ myTypeInstance);
}
 
MyType myTypeInstance;
int intVal;
 
myTypeInstance = 777;
 
intVal = myTypeInstance;
 
print "intVal = " (intVal) "\n";
print "myTypeInstance = " (intOf(myTypeInstance)) "\n";

Re: Overload the = operator
Mathias Mamsch - Mon Feb 14 16:23:05 EST 2011

Note however that a direct assignment during declaration will NOT (when I remember right from past experiments) call the assignment operator! Therefore I strongly recommend not to overwrite the assignment operator, but to use some other operator instead, like <- or <=. Also the ::= operator will shadow your DxlObject ::= operator, another reason not to use it. You can get some very hard to find errors from this ;-) All in all the below code makes it clear, that DOORS does not implement ::= operator overloading properly.

Regards, Mathias
 

struct MyType {}
void ::= (MyType &MyTypeVar, MyType blub)    { print "MyType = MyType\n"}
void ::= (MyType &MyTypeVar, int a) { print "Hallo -> " a "\n"}
 
// this works 
MyType NewMyType = null
NewMyType = 4
 
// this wont even compile:    
// MyType vvv = 15
 
// this compiles but does not call the operator!
print "In Declaration: \n"
MyType testtest = NewMyType
 
// This will call the operator ...
print "After declaration:\n"
testtest = NewMyType
 
print "\n\n"
 
// Watch out for using ::= operators ...
DxlObject x = new() 
x->"ohno" = 1 
 
int a = (x->"ohno") int
print "Uh oh: " a "\n"
 
/* prints: 
Hallo -> 4
In Declaration: 
After declaration:
MyType = MyType

Hallo -> 1
Uh oh: 0
*/

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Re: Overload the = operator
SystemAdmin - Mon Feb 14 16:34:19 EST 2011

Although I have yet to use the "return value" of the ::=(p1&,p2) function, it should be p1 (not p1& as I erroneously showed in previous post)

Corrected code is:

struct MyType {}
 
int ::= (int& intRef, MyType myTypeInstance) { 
    // local int variable gets the myTypeInstance content
    int intContent = (int addr_ myTypeInstance);
    // The passed in int reference gets the intContent
    // This is what does the LHS = RHS assignment 
    intRef = intContent;
    // Return the int content for good measure (seldom used) 
    return (intContent);
}
 
 
MyType ::= (MyType& myTypeInstanceRef, int intValue) { 
    // local MyType variable gets the intValue content
    MyType myTypeInstance = (MyType addr_ intValue)
    // The passed in MyType reference gets the myTypeInstance content
    // This is what does the LHS = RHS assignment 
    myTypeInstanceRef = myTypeInstance;
    // Return the MyType content for good measure (seldom used)
    // Allows the below to work (where j is int):
    //     print "myTypeInstance = " (j = myTypeInstance) "\n"; 
    return (myTypeInstance);
}
 
 
int intOf(MyType myTypeInstance) { 
    return (int addr_ myTypeInstance);
}
 
 
 
MyType myTypeInstance = null;
int intVal = null;
 
myTypeInstance = 777;
intVal = myTypeInstance;
 
print "intVal = " (intVal) "\n";
print "myTypeInstance = " (intOf(myTypeInstance)) "\n";
 
int j;
// The below uses the "return value" (see why I don't use it?)
print "myTypeInstance = " (j = myTypeInstance) "\n";

 


Also, understand Mathias's remark so you don't get burned.

As Clint Eastwood (as Dirty Harry) says:
"A man's got to know his limitations (as a car blows up)"

Hope that won't happen to your code :)

 

Re: Overload the = operator
Mathias Mamsch - Tue Feb 15 04:10:33 EST 2011

SystemAdmin - Mon Feb 14 16:34:19 EST 2011

Although I have yet to use the "return value" of the ::=(p1&,p2) function, it should be p1 (not p1& as I erroneously showed in previous post)

Corrected code is:

struct MyType {}
 
int ::= (int& intRef, MyType myTypeInstance) { 
    // local int variable gets the myTypeInstance content
    int intContent = (int addr_ myTypeInstance);
    // The passed in int reference gets the intContent
    // This is what does the LHS = RHS assignment 
    intRef = intContent;
    // Return the int content for good measure (seldom used) 
    return (intContent);
}
 
 
MyType ::= (MyType& myTypeInstanceRef, int intValue) { 
    // local MyType variable gets the intValue content
    MyType myTypeInstance = (MyType addr_ intValue)
    // The passed in MyType reference gets the myTypeInstance content
    // This is what does the LHS = RHS assignment 
    myTypeInstanceRef = myTypeInstance;
    // Return the MyType content for good measure (seldom used)
    // Allows the below to work (where j is int):
    //     print "myTypeInstance = " (j = myTypeInstance) "\n"; 
    return (myTypeInstance);
}
 
 
int intOf(MyType myTypeInstance) { 
    return (int addr_ myTypeInstance);
}
 
 
 
MyType myTypeInstance = null;
int intVal = null;
 
myTypeInstance = 777;
intVal = myTypeInstance;
 
print "intVal = " (intVal) "\n";
print "myTypeInstance = " (intOf(myTypeInstance)) "\n";
 
int j;
// The below uses the "return value" (see why I don't use it?)
print "myTypeInstance = " (j = myTypeInstance) "\n";

 


Also, understand Mathias's remark so you don't get burned.

As Clint Eastwood (as Dirty Harry) says:
"A man's got to know his limitations (as a car blows up)"

Hope that won't happen to your code :)

 

Don't you think that the fact that declaring a ::= operator effectively breaking all DxlObject assignments after it should prevent you from putting code like that in a library? I mean the whole idea of custom datatypes is to make libraries reusable - If I have a library that will break other libraries, that seems to me like a very bad idea. Even if you know not to use any DxlObjects after your #include the next programmer will not know this. Regards, Mathias

Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Re: Overload the = operator
SystemAdmin - Tue Feb 15 07:20:34 EST 2011

Mathias Mamsch - Tue Feb 15 04:10:33 EST 2011
Don't you think that the fact that declaring a ::= operator effectively breaking all DxlObject assignments after it should prevent you from putting code like that in a library? I mean the whole idea of custom datatypes is to make libraries reusable - If I have a library that will break other libraries, that seems to me like a very bad idea. Even if you know not to use any DxlObjects after your #include the next programmer will not know this. Regards, Mathias


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

I understand that declaring a " ::= (NewType, ExistingType) " operator breaks standard assignments. For these I tend to use "=>" instead. Is that also the case that a " ::= (ExistingType, NewType) " operator breaks standard assignments? If so I guess I'll use "=>" for those too.

Re: Overload the = operator
Mathias Mamsch - Tue Feb 15 07:53:29 EST 2011

SystemAdmin - Tue Feb 15 07:20:34 EST 2011
I understand that declaring a " ::= (NewType, ExistingType) " operator breaks standard assignments. For these I tend to use "=>" instead. Is that also the case that a " ::= (ExistingType, NewType) " operator breaks standard assignments? If so I guess I'll use "=>" for those too.

Declaring a "::=" operator will not break all standard assignments. It will specially break the DxlObject assignment. I don't think other assignments will be broken. For me the problem looks as followed: The DxlObject perms are defined as:
 

_x ::-> (DxlObject obj, string fieldName) // problem perm 
DxlObjectLHS ::-> (DxlObject obj, string fieldName)
void ::= (DxlObjectLHS lhs, _x newValue)

 


This makes no sense! The "problem perm" will match to ANY type, therefore also your custom type. And that is why DxlObject all assignments will from there on call your custom ::= operator.

 

 

 

struct MyType {}
int ::=(MyType x, int val) { print "Test:" val "\n"; return 0 }
 
DxlObject x = new() 
x->"Hallo" = 123   
// the (x->"Hallo") will be translated to the _x type, which matches MyType
 
// this works! 
(DxlObjectLHS (x->"Hallo2")) = 234



So if you are sure that there will be no DxlObject assignments now and in future after your ::= operator, then you can use the ::= operator but I would suggest you to use ::<- or something like this. The syntax is equally nice. If you don't care about a slick syntax then just use a method setValue (MyType x, int x).

Regards, Mathias



 

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Re: Overload the = operator
SystemAdmin - Tue Feb 15 08:39:41 EST 2011

Mathias Mamsch - Tue Feb 15 07:53:29 EST 2011

Declaring a "::=" operator will not break all standard assignments. It will specially break the DxlObject assignment. I don't think other assignments will be broken. For me the problem looks as followed: The DxlObject perms are defined as:
 

_x ::-> (DxlObject obj, string fieldName) // problem perm 
DxlObjectLHS ::-> (DxlObject obj, string fieldName)
void ::= (DxlObjectLHS lhs, _x newValue)

 


This makes no sense! The "problem perm" will match to ANY type, therefore also your custom type. And that is why DxlObject all assignments will from there on call your custom ::= operator.

 

 

 

struct MyType {}
int ::=(MyType x, int val) { print "Test:" val "\n"; return 0 }
 
DxlObject x = new() 
x->"Hallo" = 123   
// the (x->"Hallo") will be translated to the _x type, which matches MyType
 
// this works! 
(DxlObjectLHS (x->"Hallo2")) = 234



So if you are sure that there will be no DxlObject assignments now and in future after your ::= operator, then you can use the ::= operator but I would suggest you to use ::<- or something like this. The syntax is equally nice. If you don't care about a slick syntax then just use a method setValue (MyType x, int x).

Regards, Mathias



 

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Ok, Thanks.

I think I will just avoid this and use a GetValue method since (as you pointed out) direct assignment during declaration fails to compile:

// All fail
int intValue = NewType
int intValue => NewType
int intValue <- NewType

Re: Overload the = operator
Mathias Mamsch - Tue Feb 15 09:02:24 EST 2011

SystemAdmin - Tue Feb 15 08:39:41 EST 2011

Ok, Thanks.

I think I will just avoid this and use a GetValue method since (as you pointed out) direct assignment during declaration fails to compile:

// All fail
int intValue = NewType
int intValue => NewType
int intValue <- NewType

Yes with the <- operators you would be forced to do

int x; x <- myType

Regards, Mathias


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Re: Overload the = operator
SystemAdmin - Tue Feb 15 11:22:52 EST 2011

Mathias Mamsch - Tue Feb 15 09:02:24 EST 2011

Yes with the <- operators you would be forced to do

int x; x <- myType

Regards, Mathias


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Mathias, in a prior post in this topic where you remarked:

 

This makes no sense! The "problem perm" will match to ANY type, therefore also your custom type.
 


I concur that your example does indeed illustrate a serious problem. Please clarify the perm that is being matched and remark on some other mysterious fun facts.

Referring to the perms spreadsheet (from another post):
[A] Is the letter used in syntax <underscore><some letter> arbitrary (e.g., _m)? I was thinking it was but never formally read it anywhere.

[B] It appears most assignment operators take the form:



 

 

SomeType ::= (SomeType&, SomeOtherType);  // usage: some = someOther;

 


I was (perhaps wishfully) thinking that function matching would:

 

 

 

 

 

 

  • First look for a function that matches parameters in the calling context. For example, if a call existed (in this case an overloaded assignment) with parameters:

 

struct MyType66 {}
 
MyType66 ::= (MyType66&, int);
 
// later we have …
 
MyType66 my66;
int iFour = 4; 
my66 = iFour; // calls the overloaded (MyType66&, int)

 

 

  • Second, if no precisely matching function was found, DXL would consider the "wild-card" functions (of form "_m" or "_m&").


[C] Please explain:

 

 

 

  • What perm is getting lost in the shuffle (causing DxlObject functions to break)?
  • What is DxlObjectLHS exactly and what is the calling syntax to invoke?
  • I see perm void ::= (DxlObjectLHS lhs, _x newValue); Show code that calls this.
  • I see perm _k ::= (_k&, _k); Is this the catch-all assignment is nothing else more specific is found.


In general it looks like ::= does not behave well enough to use, but I'd like to know why in order to not get burned in similar situations.

 

Re: Overload the = operator
Mathias Mamsch - Tue Feb 15 12:31:09 EST 2011

SystemAdmin - Tue Feb 15 11:22:52 EST 2011

Mathias, in a prior post in this topic where you remarked:

 

This makes no sense! The "problem perm" will match to ANY type, therefore also your custom type.
 


I concur that your example does indeed illustrate a serious problem. Please clarify the perm that is being matched and remark on some other mysterious fun facts.

Referring to the perms spreadsheet (from another post):
[A] Is the letter used in syntax <underscore><some letter> arbitrary (e.g., _m)? I was thinking it was but never formally read it anywhere.

[B] It appears most assignment operators take the form:



 

 

SomeType ::= (SomeType&, SomeOtherType);  // usage: some = someOther;

 


I was (perhaps wishfully) thinking that function matching would:

 

 

 

 

 

 

  • First look for a function that matches parameters in the calling context. For example, if a call existed (in this case an overloaded assignment) with parameters:

 

struct MyType66 {}
 
MyType66 ::= (MyType66&, int);
 
// later we have …
 
MyType66 my66;
int iFour = 4; 
my66 = iFour; // calls the overloaded (MyType66&, int)

 

 

  • Second, if no precisely matching function was found, DXL would consider the "wild-card" functions (of form "_m" or "_m&").


[C] Please explain:

 

 

 

  • What perm is getting lost in the shuffle (causing DxlObject functions to break)?
  • What is DxlObjectLHS exactly and what is the calling syntax to invoke?
  • I see perm void ::= (DxlObjectLHS lhs, _x newValue); Show code that calls this.
  • I see perm _k ::= (_k&, _k); Is this the catch-all assignment is nothing else more specific is found.


In general it looks like ::= does not behave well enough to use, but I'd like to know why in order to not get burned in similar situations.

 

I am not completly sure about the underscore types, but I think the letter is not arbitrarily. When creating functions that operate on any type (e.g. wrappers around Skip) I always make sure that the types I take match the ones, that the skip will take. So if put (Skip, _x, _y) my function will take the same myFunc (MyType, _x, _y). It might even not be possible to choose other ones. I remember problems with that. Note that _x and _y are different types! Also note, that you can only use _ (underscore) as a type in functions. As I said I am not completely sure about the underscore types, but coming to your other questions you see that _k ::=(&_k, _k) is a perm that will only do assignments of the same type. And this is one of the "basic perms" (e.g. registered with pragma perm, ... not pragma permfn, ...), not a builtin perm I am not sure what precedence it will take it function lookup.

Anyway coming again to the "problem perm" and the breaking DxlObject assigments, if the parser comes to a statement: myDxlObject->myString = intValue, it has to get the right perm for the two operators ::-> and ::=. For ::-> it has two alternatives. For the assignments there are several possibilities. So it will (depth first recursively) try all assignments that have an int value on the right hand side. For each assignment it will try to find a ::-> perm that takes DxlObject and string as parameter and yields a compatible return value. As soon you define your own assignment operator that one will take precedence in the search order. And since unfortunately the _x ::-> operator will match to any type, the parser seemingly chooses the first valid combination (instead of checking for others and issuing a ambiguous statement error). This is all guesswork, by the way.

So the DxlObjectLHS thing is just the way you anable those var.blah = blub or var->blah = blub or function MyType[val] syntax in DXL (and this syntax is probably the reason why . and -> take precedence over other operators by the way, so you would not need to put parenthesis). DxlObjectLHS is a undocumented type which will store the DxlObject handle and the string value, and pass that to the assignent operator, which will extract the string value, the dxlobject handle from the DxlObjectLHS and then do the assignment.

Usually the _x ::-> perm is used when you do right hand assignments int x = (MyDxlObject->myString) int and it will extract the value of the DxlObject. In this case the _x variant of ::-> will be used and casted to int since there is no ::=(int, DxlObjectLHS) perm. In case of left hand assignments however ::=(DxlObjectLHS, _x) should be always be used. Since both ::-> perms for DxlObject are ambiguous the syntax only works because of the search order, i.e. in assigments the parser will consider the DxlObjectLHS operator first.

No idea if I am anywhere near the truth here. The whole thing is probably even more complicated. Regards, Mathias

Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Re: Overload the = operator
SystemAdmin - Tue Feb 15 13:03:17 EST 2011

Mathias Mamsch - Tue Feb 15 12:31:09 EST 2011
I am not completly sure about the underscore types, but I think the letter is not arbitrarily. When creating functions that operate on any type (e.g. wrappers around Skip) I always make sure that the types I take match the ones, that the skip will take. So if put (Skip, _x, _y) my function will take the same myFunc (MyType, _x, _y). It might even not be possible to choose other ones. I remember problems with that. Note that _x and _y are different types! Also note, that you can only use _ (underscore) as a type in functions. As I said I am not completely sure about the underscore types, but coming to your other questions you see that _k ::=(&_k, _k) is a perm that will only do assignments of the same type. And this is one of the "basic perms" (e.g. registered with pragma perm, ... not pragma permfn, ...), not a builtin perm I am not sure what precedence it will take it function lookup.

Anyway coming again to the "problem perm" and the breaking DxlObject assigments, if the parser comes to a statement: myDxlObject->myString = intValue, it has to get the right perm for the two operators ::-> and ::=. For ::-> it has two alternatives. For the assignments there are several possibilities. So it will (depth first recursively) try all assignments that have an int value on the right hand side. For each assignment it will try to find a ::-> perm that takes DxlObject and string as parameter and yields a compatible return value. As soon you define your own assignment operator that one will take precedence in the search order. And since unfortunately the _x ::-> operator will match to any type, the parser seemingly chooses the first valid combination (instead of checking for others and issuing a ambiguous statement error). This is all guesswork, by the way.

So the DxlObjectLHS thing is just the way you anable those var.blah = blub or var->blah = blub or function MyType[val] syntax in DXL (and this syntax is probably the reason why . and -> take precedence over other operators by the way, so you would not need to put parenthesis). DxlObjectLHS is a undocumented type which will store the DxlObject handle and the string value, and pass that to the assignent operator, which will extract the string value, the dxlobject handle from the DxlObjectLHS and then do the assignment.

Usually the _x ::-> perm is used when you do right hand assignments int x = (MyDxlObject->myString) int and it will extract the value of the DxlObject. In this case the _x variant of ::-> will be used and casted to int since there is no ::=(int, DxlObjectLHS) perm. In case of left hand assignments however ::=(DxlObjectLHS, _x) should be always be used. Since both ::-> perms for DxlObject are ambiguous the syntax only works because of the search order, i.e. in assigments the parser will consider the DxlObjectLHS operator first.

No idea if I am anywhere near the truth here. The whole thing is probably even more complicated. Regards, Mathias


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Mathias,

Thanks. This is great information even if some of it is empirical. This is a regular circus. How I wish could have a sodium pentothal party with some of those original DXL architects and find out what they were thinking.

Curiously, the DxlObjectLHS parameter is passed by value and not by reference like the other assignment overload functions. I can only assume it must already be a reference (have a reference to the DxlObject) in order to work. Do you know the field structure?

Re: Overload the = operator
SystemAdmin - Thu Feb 17 16:20:51 EST 2011

Mathias Mamsch - Tue Feb 15 12:31:09 EST 2011
I am not completly sure about the underscore types, but I think the letter is not arbitrarily. When creating functions that operate on any type (e.g. wrappers around Skip) I always make sure that the types I take match the ones, that the skip will take. So if put (Skip, _x, _y) my function will take the same myFunc (MyType, _x, _y). It might even not be possible to choose other ones. I remember problems with that. Note that _x and _y are different types! Also note, that you can only use _ (underscore) as a type in functions. As I said I am not completely sure about the underscore types, but coming to your other questions you see that _k ::=(&_k, _k) is a perm that will only do assignments of the same type. And this is one of the "basic perms" (e.g. registered with pragma perm, ... not pragma permfn, ...), not a builtin perm I am not sure what precedence it will take it function lookup.

Anyway coming again to the "problem perm" and the breaking DxlObject assigments, if the parser comes to a statement: myDxlObject->myString = intValue, it has to get the right perm for the two operators ::-> and ::=. For ::-> it has two alternatives. For the assignments there are several possibilities. So it will (depth first recursively) try all assignments that have an int value on the right hand side. For each assignment it will try to find a ::-> perm that takes DxlObject and string as parameter and yields a compatible return value. As soon you define your own assignment operator that one will take precedence in the search order. And since unfortunately the _x ::-> operator will match to any type, the parser seemingly chooses the first valid combination (instead of checking for others and issuing a ambiguous statement error). This is all guesswork, by the way.

So the DxlObjectLHS thing is just the way you anable those var.blah = blub or var->blah = blub or function MyType[val] syntax in DXL (and this syntax is probably the reason why . and -> take precedence over other operators by the way, so you would not need to put parenthesis). DxlObjectLHS is a undocumented type which will store the DxlObject handle and the string value, and pass that to the assignent operator, which will extract the string value, the dxlobject handle from the DxlObjectLHS and then do the assignment.

Usually the _x ::-> perm is used when you do right hand assignments int x = (MyDxlObject->myString) int and it will extract the value of the DxlObject. In this case the _x variant of ::-> will be used and casted to int since there is no ::=(int, DxlObjectLHS) perm. In case of left hand assignments however ::=(DxlObjectLHS, _x) should be always be used. Since both ::-> perms for DxlObject are ambiguous the syntax only works because of the search order, i.e. in assigments the parser will consider the DxlObjectLHS operator first.

No idea if I am anywhere near the truth here. The whole thing is probably even more complicated. Regards, Mathias


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Adding a DxlObjectLHS typecast to force the proper DXL native perm call will undo the bug. I think the bug stems from DXL authors using the same syntax to set/get DxlObject fields depending on context.

This is only a clue to what the problem is as I could not expect all concerned to put type casts everywhere DxlObject fields are set.

See the last couple of code lines for code kludge:
 

struct MyType {}
void ::= (MyType &MyTypeVar, MyType blub)   { print "MyType = MyType\n"}
void ::= (MyType &MyTypeVar, int a) { print "Hallo -> " a "\n"}
 
// this works 
MyType NewMyType = null
NewMyType = 4
 
// this wont even compile:    
// MyType vvv = 15
 
// this compiles but does not call the operator!
print "In Declaration: \n"
MyType testtest = NewMyType
 
// This will call the operator ...
print "After declaration:\n"
testtest = NewMyType
 
print "\n\n"
 
// Watch out for using ::= operators ...
DxlObject x = new() 
x->"ohno" = 1 
 
int a = (x->"ohno") int
print "Uh oh: " a "\n"
 
(DxlObjectLHS x->"thisWorks") = 2 
 
int b = (x->"thisWorks") int
print "thisWorks: " b "\n"
 
 
/* prints: 
Hallo -> 4
In Declaration: 
After declaration:
MyType = MyType

Hallo -> 1
Uh oh: 0
thisWorks: 2
 
*/

 


Cheers

 

Re: Overload the = operator
SystemAdmin - Fri Feb 18 08:19:25 EST 2011

Don't do it. Use a different operator.

Re: Overload the = operator
SystemAdmin - Fri Feb 18 08:21:46 EST 2011

SystemAdmin - Fri Feb 18 08:19:25 EST 2011
Don't do it. Use a different operator.

That last post wasn't aimed at anybody! It was my "Answered" summary which I didn't realise would appear like that!